package com.ithuameng.admin.interceptor;

import com.ithuameng.admin.constants.CommonConstants;
import com.ithuameng.admin.security.JwtTokenProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

import static org.apache.commons.lang3.StringUtils.removeStart;

@Slf4j
@Component
public class JwtAuthenticationFilter extends GenericFilterBean {

    @Resource
    private JwtTokenProvider jwtTokenProvider;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * <pre>
     *  在filterChain中注册一个过滤器，用于验证通过Request进入的Jwt Token的有效性
     * </pre>
     *
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 判断token是否为空
        HttpServletRequest req = (HttpServletRequest) request;
        String token = jwtTokenProvider.resolveToken(req);
        if (token == null) {
            chain.doFilter(request, response);
            return;
        }
        // 解决单用户重新登录死循环
        String uri = req.getRequestURI();
        if (uri.startsWith("/admin/v1/account/logout")) {
            chain.doFilter(request, response);
            return;
        }
        String jwtToken = removeStart(token, CommonConstants.BEARER);
        if (jwtTokenProvider.validateToken(jwtToken)) {
            Map<String, String> params = jwtTokenProvider.verify(jwtToken);
            String userToken = params.get(CommonConstants.USER_TOKEN);
            String userIdStr = params.get(CommonConstants.USER_ID);
            String userLatestToken = redisTemplate.opsForValue().get(CommonConstants.REIDS_KEY_PWY_TOKEN + userIdStr);
            if (userToken == null || userLatestToken == null || !userToken.equals(userLatestToken)) {
                RequestDispatcher rd = request.getRequestDispatcher("/admin/v1/common/error/multilogin");
                rd.forward(request, response);
                return;
            }
            if (uri.startsWith("/admin")) {
                try {
                    Authentication auth = jwtTokenProvider.getAdminAuthentication(jwtToken);
                    SecurityContextHolder.getContext().setAuthentication(auth);
                } catch (Exception e) {
                    log.error("JWT filter error.", e);
                    RequestDispatcher rd = request.getRequestDispatcher("/admin/v1/common/error/unauthorized");
                    rd.forward(request, response);
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }
}
